#pragma once

#include <algorithm>
#include <cstring>

#include "ezstl_construct.hpp"
#include "ezstl_iterator_base.hpp"
#include "type_traits.hpp"

namespace ezstl {

template <typename InputIterator, typename ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first,
                                          InputIterator last,
                                          ForwardIterator result) {
  /* POD 意指 Plain Old Data， 也就是标量类别（scalar types）或传统的 C struct
     类型。 POD 必然拥有 trivial ctor / dtor / copy / assignment 函数，因此 可对
     POD 类型使用最有效率的初值填写手法
   */
  using T = typename iterator_traits<ForwardIterator>::value_type;
  if constexpr (is_pod<T>::value) {
    // TODO: POD type replace ezstl::copy
    return std::copy(first, last, result);
  } else {  // non POD
    ForwardIterator current = result;
    try {
      for (; first != last; ++first, ++current) construct(&(*current), *first);
      return current;
    } catch (...) {
      ezstl::destroy(result, current);
      throw;
    }
  }
}

inline char *uninitialized_copy(const char *first, const char *last,
                                char *result) {
  memmove(result, first, last - first);
  return result + (last - first);
}

template <typename InputIterator, typename Size, typename ForwardIterator>
ForwardIterator uninitialized_copy_n(InputIterator first, Size count,
                                     ForwardIterator result) {}

template <typename ForwardIterator, typename T>
inline void uninitialized_fill(ForwardIterator first, ForwardIterator last,
                               const T &value) {
  using FItT = typename iterator_traits<ForwardIterator>::value_type;
  if constexpr (is_pod<FItT>::value) {
    // TODO: POD type replace ezstl::fill
    std::fill(first, last, value);
  } else {
    ForwardIterator current = first;
    try {
      for (; current != last; ++current) construct(&(*current), value);
    } catch (...) {
      ezstl::destroy(first, current);
      throw;
    }
  }
}

template <typename ForwardIterator, typename Size, typename T>
inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n,
                                            const T &value) {
  using FItT = typename iterator_traits<ForwardIterator>::value_type;
  if constexpr (is_pod<FItT>::value) {
    // TODO: POD type replace ezstl::fill_n
    return std::fill_n(first, n, value);
  } else {
    ForwardIterator current = first;
    try {
      for (; n > 0; --n, ++current) construct(current, value);
      return current;
    } catch (...) {
      ezstl::destroy(first, current);
      throw;
    }
  }
}

}  // namespace ezstl